/**
 * 
 */
package com.dalonedrau.jogl.opengl.ui;

import java.awt.Dimension;

import com.dalonedrau.jogl.engine.Animation;
import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.Interactive;
import com.dalonedrau.jogl.engine.JOGLErrorHandler;
import com.dalonedrau.jogl.engine.Render;
import com.dalonedrau.jogl.engine.Sprite;
import com.dalonedrau.jogl.opengl.GameFont;
import com.dalonedrau.jogl.opengl.animation.AnimationSequenceObjectFactory;
import com.dalonedrau.jogl.opengl.sprite.BasicSpriteObject;
import com.dalonedrau.jogl.opengl.sprite.FontsheetObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteBase;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.rpg.base.interactive.flyweight.BaseInteractiveObject;

/**
 * @author Donald
 */
public final class TextField extends GuiTextItemImpl {
	private int						charWidth		= 0;
	private BaseInteractiveObject	cursor;
	private int						length;
	private int						maxLength;
	/** the <code>TextField</code>'s preferred size. */
	private Dimension				preferredSize	= new Dimension(0, 0);
	private char[]					value;
	/**
	 * Creates a new instance of {@link TextField}.
	 * @param fontName
	 * @param size
	 */
	public TextField(final String fontName, final int size) {
		super(fontName, "");
		value = new char[size * 2];
		maxLength = size;
		super.setInsets(4, 5, 4, 5);
		// create cursor
		try {
			cursor =
					(BaseInteractiveObject) Interactive.getInstance()
							.getNewIO();
			SpriteBase sb = new BasicSpriteObject();
			SpriteImageObject img =
					SpriteImageObjectFactory.getInstance().getImageByName(
							"lunchds_18_input_cursor_0");
			sb.setImageRefId(img.getRefId());
			sb.setWidth(img.getWidth());
			sb.setHeight(img.getHeight());
			cursor.setSprite(sb);
			cursor.addAnimation(
					"blinking",
					AnimationSequenceObjectFactory.getInstance()
							.getSequenceRefId("lunchds_18_input_cursor")
					);
			Animation.getInstance().playAnimation(cursor,
					cursor.getAnimation("blinking"));
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	public void addCharacter(final char c) throws Exception {
		// add a character and a space
		if (length < maxLength) {
			value[length * 2] = c;
			// only add space when there is more
			if (length < maxLength - 1) {
				value[length * 2 + 1] = ' ';
			}
			length++;
		} else {
			value[(length - 1) * 2] = c;
		}
		resetText();
		// shift I-bar to right

		// re-size text
		// reposition text;
		preferredSize.width = 0;
		getPreferredSize();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Dimension getPreferredSize() {
		if (preferredSize.width == 0
				|| preferredSize.height == 0) {
			// ***************************************
			// ** CALCULATE THE SIZE OF THE UI WIDGET
			// ***************************************
			int w = 0, h = 0;
			// add border insets to width and height
			if (super.getBorder() != null) {
				w = super.getBorder().getInsets().left;
				w += super.getBorder().getInsets().right;
				h = super.getBorder().getInsets().top;
				h += super.getBorder().getInsets().bottom;
			}
			// remove insets from preferred width before sizing text
			// add label insets to width and height
			w += super.getInsets().left + super.getInsets().right;
			h += super.getInsets().top + super.getInsets().bottom;
			// this is a text label
			try {
				FontsheetObject font =
						GameFont.getInstance()
								.getFontById(super.getFontRefId());
				if (font.isMonospaced()) {
					font.setGlyph(' ');
					charWidth = font.getCharWidth();
					h += font.getCharHeight();
					w += charWidth * maxLength;
					w += charWidth * (maxLength - 1);
				} else {
					// TO DO - handle NON-MONOSPACED
				}
				Sprite.getInstance().computeFullStats(super.getTextGroup());
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
			preferredSize.width = w;
			preferredSize.height = h;
			if (super.getBorder() != null) {
				super.getBorder().setPreferredSize(w, h);
			}
			try {
				// ***************************************
				// ** POSITION ALL TEXT
				// ***************************************
				if (super.getPosition() != null) {
					if (super.getBorder() != null) {
						super.getBorder().setPosition(
								super.getPosition().getX(),
								super.getPosition().getY(),
								super.getPosition().getZ()
								);
					}
					positionCursor();
				}
				positionText();
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
		return preferredSize;
	}
	/**
	 * Gets the {@link TextField}'s value.
	 * @return {@link String}
	 */
	public String getValue() {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < length * 2; i += 2) {
			sb.append(value[i]);
		}
		String val = sb.toString();
		sb.returnToPool();
		return val;
	}
	private void positionCursor() {
		if (super.getPosition() != null) {
			// position the cursor
			double x = super.getPosition().getX(), y = super.getPosition()
					.getY();
			// move in from border insets
			if (super.getBorder() != null) {
				x += super.getBorder().getInsets().left;
				y += super.getBorder().getInsets().bottom;
			}

			// what is the current position
			int offset = length * 2 * charWidth;
			if (length >= maxLength) {
				offset = (length - 1) * 2 * charWidth;
			}
			x += offset;
			cursor.getSprite().setPosition(
					x,
					y + 2,
					super.getPosition().getZ()
							+ GlobalConsts.CHILD_STEP * 0.4f
					);
		}
	}
	/**
	 * Positions all text within the {@link TextField}'s boundaries.
	 * @throws Exception if an error occurs
	 */
	private void positionText() throws Exception {
		if (super.getPosition() != null && super.getTextGroup() != null) {
			super.getTextGroup().clearFloatStore();
			int height = getPreferredSize().height;
			// text position is set relative to component position
			// when component position changes, the text position doesn't need
			// to be re-calibrated
			double x = 0, y = 0;
			// move in from border insets
			if (super.getBorder() != null) {
				x += super.getBorder().getInsets().left;
				y += super.getBorder().getInsets().bottom;
				height -= super.getBorder().getInsets().top;
				height -= super.getBorder().getInsets().bottom;
			}
			// move up from label insets
			x += super.getInsets().left;
			y += super.getInsets().bottom;
			height -= super.getInsets().top;
			height -= super.getInsets().bottom;
			super.getTextGroup()
					.setPosition(
							x,
							y,
							super.getPosition().getZ()
									+ GlobalConsts.CHILD_STEP * 0.3f,
							height,
							GuiComponent.CENTER
					);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void prepareForRendering() throws Exception {
		super.prepareForRendering();
		Render.getInstance().registerEntity(cursor.getSprite());
	}
	public void removeCharacter() throws Exception {
		length--;
		if (length < 0) {
			length = 0;
		}
		resetText();
	}
	private void resetText() throws Exception {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		int totalLength = length * 2;
		if (length >= maxLength) {
			totalLength = length * 2 - 1;
		}
		for (int i = 0; i < totalLength; i++) {
			sb.append(value[i]);
		}
		super.getTextGroup().clearLines();
		super.getTextGroup().addLine(
				getPreferredSize().width,
				GuiComponent.LEFT,
				sb.toString()
				);
		sb.returnToPool();
		preferredSize.width = 0;
		getPreferredSize();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPosition(final double x, final double y, final double z) {
		boolean mustPositionText = false;
		if (super.getPosition() == null) {
			mustPositionText = true;
		}
		super.setPosition(x, y, z);
		if (mustPositionText) {
			try {
				positionText();
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
		// position the cursor
		positionCursor();
	}
}
